<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
	</head>
	<body>
		<script type="text/javascript">
			/**
			 * 原型prototype
			 * 我们创建的每一个函数，解析器都会向函数中添加一个prototype属性
			 * 这个属性对应着一个对象，这个对象就是我们所谓的原型对象
			 * 
			 * 如果函数作为普通函数使用，那么prototype不会有任何作用
			 * 但函数以构造函数的方式调用时，它所创建的对象都有一个隐含的属性，
			 * 	指向该构造函数的原型对象，用__proto__访问该属性
			 * */
			 
			 function Person(){
			 }
			 console.log(Person.prototype);
			 
			 function Myclass(){
			 }
			 console.log(Myclass.prototype);
			 
			 //每一个函数的prototype属性都不一样，这里永远是false
			 console.log("Person.prototype == Myclass.prototype ： " + (Person.prototype == Myclass.prototype));
			 
			 /**
			  * 实例共享的属性和方法，可以放在prototype中，既可以只产生一个对象，又不会污染全局作用域
			  * */
			 function Cat(){
				 
			 }
			 Cat.prototype.name = "我是原型中的名字喵";
			 Cat.prototype.sayHi = function(){
				console.log("Hello World");
			 }
			 
			 var cat1 = new Cat();
			 cat1.sayHi();
			 // cat1.__proto__ 访问其构造函数的原型对象
			 console.log("cat1.__proto__ == Cat.prototype: " + (cat1.__proto__ == Cat.prototype));
			 var cat2 = new Cat();
			 cat2.sayHi();
			 
			 //使用in检查对象中是否有某个元素，如果对象中没有但原型中有，也会返回true
			 console.log("name" in cat1);
			 //cat1.hasOwnProperty() 检查对象自身中是否有某个属性
			 console.log("cat1对象本身中有name属性： " + cat1.hasOwnProperty("name"));
			 console.log("cat1 所指向的原型对象中有name属性： " + cat1.__proto__.hasOwnProperty("name"));
			 
			 /**
			  * 原型对象也是对象，所以它也有原型
			  * 	当我们使用一个对象或方法的时候，会先去自身寻找，	
			  * 		自身没有时会去原型对象中寻找，如果原型对象中有，则使用；
			  * 		原型对象中没有，则继续去原型对象的原型中寻找，直到找到Object对象的原型；
			  * 		Object对象的原型没有原型，如果在Object中依然没有找到，则返回undefined
			  * */
			  
			  function Dog(){
				  
			  }
			  Dog.prototype.name = "汪汪汪";
			  Dog.prototype.drink = function(){
				  console.log("我是构造函数里的小狗狗，我在喝水");
			  }
			  
			  var dog1 = new Dog();
			  /**
			   * 直接输出dog1和输出dog1.toString()是一样的，
			   * 实际上我们输出的都是toString()的返回值。
			   * 如果我们不希望输出的对象是[object object],可以自己为对象添加一个toString()
			   * */
			  console.log(typeof(dog1));
			  console.log(dog1);
			  var result = dog1.toString();
			  console.log(result);
			  console.log(dog1.toString());
			  //dog1本身没有toString()
			  console.log(dog1.hasOwnProperty("toString"));
			  //dog1的构造方法的原型也没有toString()
			  console.log(dog1.__proto__.hasOwnProperty("toString"));
			  //dog1的构造方法的原型的原型有toString()方法
			  console.log(dog1.__proto__.__proto__.hasOwnProperty("toString"));
			  
			  dog1.toString = function(){
				  return("我是dog1的toString()");
			  }
			  console.log(dog1);
			  //给对象dog1添加里一个toString()，只有dog1能用
			  console.log(dog1.hasOwnProperty("toString"));
			  
			  var dog2 = new Dog();
			  //dog2不能使用给dog1添加的toString()
			  console.log(dog2.hasOwnProperty("toString"));
			  
			  // 给构造方法的原型添加新的toString()后,新建的所有对象都可以使用此方法
			  Dog.prototype.toString = function(){
				  return("我是构造方法中的toString()");
			  }
			  
			  var dog3 = new Dog();
			  console.log(dog3.toString());
			  console.log(dog3.__proto__.hasOwnProperty("toString"));
			  var dog4 = new Dog();
			  console.log(dog4.toString());
			  console.log(dog4.__proto__.hasOwnProperty("toString"));
		</script>
	</body>
	
</html>
